package com.chery.foxlogrecord.extension.operation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chery.foxlogrecord.core.enums.EditType;
import com.chery.foxlogrecord.core.pojo.FieldDiffDTO;
import com.chery.foxlogrecord.core.pojo.ObjectDiffDTO;
import com.chery.foxlogrecord.core.service.ObjectDiffService;
import com.chery.foxlogrecord.core.util.PatternUtils;
import com.chery.foxlogrecord.extension.operation.disruptor.DisruptorPublisher;
import com.chery.foxlogrecord.extension.operation.entity.Operation;
import com.chery.foxlogrecord.extension.operation.entity.OperationField;
import com.chery.foxlogrecord.extension.operation.mapper.OperationMapper;
import com.chery.foxlogrecord.extension.operation.pojo.dto.OperationFieldVO;
import com.chery.foxlogrecord.extension.operation.pojo.dto.OperationPageDto;
import com.chery.foxlogrecord.extension.operation.pojo.dto.OperationPageVO;
import com.chery.foxlogrecord.extension.operation.service.OperationFieldService;
import com.chery.foxlogrecord.extension.operation.service.OperationService;
import com.chery.foxlogrecord.extension.security.ResourceOwnerContext;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;

/**
 * @author qiangt
 * @version 1.0
 * @date 2023/12/5 11:11
 * @description: 操作记录service
 */
@RequiredArgsConstructor
@Validated
@Service
public class OperationServiceImpl extends ServiceImpl<OperationMapper, Operation>
        implements OperationService, ObjectDiffService {

    private final OperationFieldService operationFieldService;
    /** 当前登录人 */
    private final ResourceOwnerContext resourceOwnerContext;

    @Override
    public Page<Operation> pageByBusinessId(@Valid OperationPageDto pageDto) {
        Page<Operation> page = new Page<>(pageDto.getPageCurrent(), pageDto.getPageSize());
        String orderSql = pageDto.getOrderSql();
        return this.lambdaQuery()
                .eq(Operation::getBusinessId, pageDto.getBusinessId())
                .eq(Operation::getModule, pageDto.getModule())
                .eq(ObjectUtil.isNotNull(pageDto.getType()), Operation::getType, pageDto.getType())
                .eq(StrUtil.isNotBlank(pageDto.getOperatorName()), Operation::getOperatorName, pageDto.getOperatorName())
                .ge(ObjectUtil.isNotNull(pageDto.getOperationStartTime()), Operation::getCreateTime,
                        pageDto.getOperationStartTime())
                .le(ObjectUtil.isNotNull(pageDto.getOperationEndTime()), Operation::getCreateTime,
                        pageDto.getOperationEndTime())
                .last(StrUtil.isNotBlank(orderSql), orderSql)
                .orderByDesc(StrUtil.isBlank(orderSql), Operation::getCreateTime)
                .page(page);
    }

    @Override
    public Page<OperationPageVO> pageDetailByBusinessId(OperationPageDto pageDto) {
        Page<Operation> page = new Page<>(pageDto.getPageCurrent(), pageDto.getPageSize());
        String orderSql = pageDto.getOrderSql();
        Page<Operation> result = this.lambdaQuery()
                .eq(Operation::getBusinessId, pageDto.getBusinessId())
                .eq(Operation::getModule, pageDto.getModule())
                .eq(ObjectUtil.isNotNull(pageDto.getType()), Operation::getType, pageDto.getType())
                .eq(StrUtil.isNotBlank(pageDto.getOperatorName()), Operation::getOperatorName, pageDto.getOperatorName())
                .ge(ObjectUtil.isNotNull(pageDto.getOperationStartTime()), Operation::getCreateTime,
                        pageDto.getOperationStartTime())
                .le(ObjectUtil.isNotNull(pageDto.getOperationEndTime()), Operation::getCreateTime,
                        pageDto.getOperationEndTime())
                .last(StrUtil.isNotBlank(orderSql), orderSql)
                .orderByDesc(StrUtil.isBlank(orderSql), Operation::getCreateTime)
                .page(page);
        // 填充操作记录描述
        List<OperationPageVO> operationPageVOList = BeanUtil.copyToList(result.getRecords(), OperationPageVO.class);
        if (CollectionUtil.isNotEmpty(operationPageVOList)) {
            List<OperationFieldVO> operationFieldVOList = new ArrayList<>();
            for (OperationPageVO operation : operationPageVOList) {
                List<OperationField> list = operationFieldService.lambdaQuery().eq(OperationField::getOperationId, operation.getId()).list();
                if (CollectionUtil.isNotEmpty(list)) {
                    for (OperationField operationField : list) {
                        OperationFieldVO operationFieldVO = BeanUtil.toBean(operationField, OperationFieldVO.class);
                        String desc = "";
                        if (EditType.SAVE.equals(operationField.getChangeType())) {
                            desc = PatternUtils.formatPlaceholder(EditType.SAVE.getTemplate(), operationField.getFieldNameShow(), operationField.getFieldAfterShow());
                        } else if (EditType.UPDATE.equals(operationField.getChangeType())) {
                            desc = PatternUtils.formatPlaceholder(EditType.UPDATE.getTemplate(), operationField.getFieldNameShow(), operationField.getFieldBeforeShow(), operationField.getFieldAfterShow());
                        } else if (EditType.DELETE.equals(operationField.getChangeType())) {
                            desc = PatternUtils.formatPlaceholder(EditType.DELETE.getTemplate(), operationField.getFieldNameShow(), operationField.getFieldBeforeShow());
                        }
                        operationFieldVO.setDesc(desc);
                        operationFieldVOList.add(operationFieldVO);
                    }
                    operation.setOperationFieldVOList(operationFieldVOList);
                }
            }
        }
        Page<OperationPageVO> pageVO = new Page<>(page.getCurrent(), page.getSize(), result.getTotal());
        pageVO.setRecords(operationPageVOList);
        return pageVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(ObjectDiffDTO objectDiffDTO) {
        objectDiffDTO.setOperatorName(resourceOwnerContext.getPrincipal().getName());
        DisruptorPublisher.send(objectDiffDTO);
    }

    @Override
    public void asycSave(ObjectDiffDTO objectDiffDTO) {
        // 存入操作记录表
        Operation operation = new Operation();
        operation.setBusinessId(Convert.toLong(objectDiffDTO.getBusinessId()));
        operation.setModule(objectDiffDTO.getModule());
        operation.setType(objectDiffDTO.getLogOperate());
        operation.setDescription(objectDiffDTO.getDescription());
        operation.setClassBefore(objectDiffDTO.getOldClassName());
        operation.setClassAfter(objectDiffDTO.getNewClassName());
        operation.setJsonBefore(objectDiffDTO.getJsonBefore());
        operation.setJsonAfter(objectDiffDTO.getJsonAfter());
        operation.setOperatorName(objectDiffDTO.getOperatorName());
        this.save(operation);
        // 存入操作记录字段表
        List<FieldDiffDTO> fieldDiffDTOList = objectDiffDTO.getFieldDiffDTOList();
        for (FieldDiffDTO fieldDiffDTO : fieldDiffDTOList) {
            OperationField operationField = new OperationField();
            operationField.setOperationId(operation.getId());
            operationField.setFieldName(fieldDiffDTO.getFieldName());
            operationField.setFieldNameShow(fieldDiffDTO.getName());
            operationField.setChangeType(fieldDiffDTO.getEditType());
            operationField.setFieldBefore(Convert.toStr(fieldDiffDTO.getOldValue()));
            operationField.setFieldBeforeShow(Convert.toStr(fieldDiffDTO.getOldValueShow()));
            operationField.setFieldAfter(Convert.toStr(fieldDiffDTO.getNewValue()));
            operationField.setFieldAfterShow(Convert.toStr(fieldDiffDTO.getNewValueShow()));
            operationFieldService.save(operationField);
        }
    }
}
